#!/bin/sh
#
# Run the code in test.jar on the device. The jar should contain a top-level
# class named Main to run.

msg() {
    if [ "$QUIET" = "n" ]; then
        echo "$@"
    fi
}

ARCHITECTURES_32="(arm|x86|mips|none)"
ARCHITECTURES_64="(arm64|x86_64|none)"
ARCHITECTURES_PATTERN="${ARCHITECTURES_32}"
RELOCATE="y"
GDB="n"
DEBUGGER="n"
INTERPRETER="n"
VERIFY="y"
OPTIMIZE="y"
ZYGOTE=""
QUIET="n"
DEV_MODE="n"
INVOKE_WITH=""
FLAGS=""
TARGET_SUFFIX="32"
GDB_TARGET_SUFFIX=""
COMPILE_FLAGS=""
SECONDARY_DEX=""
DEX_VERIFY=""

while true; do
    if [ "x$1" = "x--quiet" ]; then
        QUIET="y"
        shift
    elif [ "x$1" = "x--lib" ]; then
        shift
        if [ "x$1" = "x" ]; then
            echo "$0 missing argument to --lib" 1>&2
            exit 1
        fi
        LIB="$1"
        shift
    elif [ "x$1" = "x-Xcompiler-option" ]; then
        shift
        option="$1"
        FLAGS="${FLAGS} -Xcompiler-option $option"
        COMPILE_FLAGS="${COMPILE_FLAGS} $option"
        shift
    elif [ "x$1" = "x--runtime-option" ]; then
        shift
        option="$1"
        FLAGS="${FLAGS} $option"
        shift
    elif [ "x$1" = "x--boot" ]; then
        shift
        BOOT_OPT="$1"
        BUILD_BOOT_OPT="--boot-image=${1#-Ximage:}"
        shift
    elif [ "x$1" = "x--relocate" ]; then
        RELOCATE="y"
        shift
    elif [ "x$1" = "x--no-relocate" ]; then
        RELOCATE="n"
        shift
    elif [ "x$1" = "x--debug" ]; then
        DEBUGGER="y"
        shift
    elif [ "x$1" = "x--gdb" ]; then
        GDB="y"
        DEV_MODE="y"
        shift
    elif [ "x$1" = "x--zygote" ]; then
        ZYGOTE="--zygote"
        msg "Spawning from zygote"
        shift
    elif [ "x$1" = "x--dev" ]; then
        DEV_MODE="y"
        shift
    elif [ "x$1" = "x--interpreter" ]; then
        INTERPRETER="y"
        shift
    elif [ "x$1" = "x--invoke-with" ]; then
        shift
        if [ "x$1" = "x" ]; then
            echo "$0 missing argument to --invoke-with" 1>&2
            exit 1
        fi
        if [ "x$INVOKE_WITH" = "x" ]; then
            INVOKE_WITH="$1"
        else
            INVOKE_WITH="$INVOKE_WITH $1"
        fi
        shift
    elif [ "x$1" = "x--no-verify" ]; then
        VERIFY="n"
        shift
    elif [ "x$1" = "x--no-optimize" ]; then
        OPTIMIZE="n"
        shift
    elif [ "x$1" = "x--" ]; then
        shift
        break
    elif [ "x$1" = "x--64" ]; then
        TARGET_SUFFIX="64"
        GDB_TARGET_SUFFIX="64"
        ARCHITECTURES_PATTERN="${ARCHITECTURES_64}"
        shift
    elif [ "x$1" = "x--secondary" ]; then
        SECONDARY_DEX=":$DEX_LOCATION/$TEST_NAME-ex.jar"
        shift
    elif expr "x$1" : "x--" >/dev/null 2>&1; then
        echo "unknown $0 option: $1" 1>&2
        exit 1
    else
        break
    fi
done

if [ "$ZYGOTE" = "" ]; then
    if [ "$OPTIMIZE" = "y" ]; then
        if [ "$VERIFY" = "y" ]; then
            DEX_OPTIMIZE="-Xdexopt:verified"
        else
            DEX_OPTIMIZE="-Xdexopt:all"
        fi
        msg "Performing optimizations"
    else
        DEX_OPTIMIZE="-Xdexopt:none"
        msg "Skipping optimizations"
    fi

    if [ "$VERIFY" = "y" ]; then
        msg "Performing verification"
    else
        DEX_VERIFY="-Xverify:none"
        msg "Skipping verification"
    fi
fi

msg "------------------------------"

ARCH=$(adb shell ls -F /data/dalvik-cache | grep -Ewo "${ARCHITECTURES_PATTERN}")
if [ x"$ARCH" = "x" ]; then
  echo "Unable to determine architecture"
  exit 1
fi

if [ "$QUIET" = "n" ]; then
  adb shell rm -r $DEX_LOCATION
  adb shell mkdir -p $DEX_LOCATION
  adb push $TEST_NAME.jar $DEX_LOCATION
  adb push $TEST_NAME-ex.jar $DEX_LOCATION
else
  adb shell rm -r $DEX_LOCATION >/dev/null 2>&1
  adb shell mkdir -p $DEX_LOCATION >/dev/null 2>&1
  adb push $TEST_NAME.jar $DEX_LOCATION >/dev/null 2>&1
  adb push $TEST_NAME-ex.jar $DEX_LOCATION >/dev/null 2>&1
fi

if [ "$DEBUGGER" = "y" ]; then
  # Use this instead for ddms and connect by running 'ddms':
  # DEBUGGER_OPTS="-agentlib:jdwp=transport=dt_android_adb,server=y,suspend=y"
  # TODO: add a separate --ddms option?

  PORT=12345
  msg "Waiting for jdb to connect:"
  msg "    adb forward tcp:$PORT tcp:$PORT"
  msg "    jdb -attach localhost:$PORT"
  DEBUGGER_OPTS="-agentlib:jdwp=transport=dt_socket,address=$PORT,server=y,suspend=y"
fi

if [ "$GDB" = "y" ]; then
    gdb="gdbserver$GDB_TARGET_SUFFIX :5039"
    gdbargs="$exe"
fi

if [ "$INTERPRETER" = "y" ]; then
    INT_OPTS="-Xint"
    if [ "$VERIFY" = "y" ] ; then
      COMPILE_FLAGS="${COMPILE_FLAGS} --compiler-filter=interpret-only"
    else
      COMPILE_FLAGS="${COMPILE_FLAGS} --compiler-filter=verify-none"
      DEX_VERIFY="${DEX_VERIFY} -Xverify:none"
    fi
fi

JNI_OPTS="-Xjnigreflimit:512 -Xcheck:jni"

if [ "$RELOCATE" = "y" ]; then
    RELOCATE_OPT="-Xrelocate"
    BUILD_RELOCATE_OPT="--runtime-arg -Xnorelocate"
    COMPILE_FLAGS="${COMPILE_FLAGS} --include-patch-information"
    FLAGS="${FLAGS} -Xcompiler-option --include-patch-information"
else
    RELOCATE_OPT="-Xnorelocate"
    BUILD_RELOCATE_OPT="--runtime-arg -Xnorelocate"
fi

# This is due to the fact this cmdline can get longer than the longest allowed
# adb command and there is no way to get the exit status from a adb shell
# command.
cmdline="cd $DEX_LOCATION && export ANDROID_DATA=$DEX_LOCATION && export DEX_LOCATION=$DEX_LOCATION && \
    mkdir -p $DEX_LOCATION/dalvik-cache/$ARCH/ && \
    $INVOKE_WITH /system/bin/dex2oatd $COMPILE_FLAGS $BUILD_BOOT_OPT $BUILD_RELOCATE_OPT  --runtime-arg -classpath --runtime-arg $DEX_LOCATION/$TEST_NAME.jar --dex-file=$DEX_LOCATION/$TEST_NAME.jar --oat-file=$DEX_LOCATION/dalvik-cache/$ARCH/$(echo $DEX_LOCATION/$TEST_NAME.jar/classes.dex | cut -d/ -f 2- | sed "s:/:@:g") --instruction-set=$ARCH && \
    $INVOKE_WITH $gdb /system/bin/dalvikvm$TARGET_SUFFIX $FLAGS $gdbargs -XXlib:$LIB $ZYGOTE $JNI_OPTS $RELOCATE_OPT $INT_OPTS $DEBUGGER_OPTS $BOOT_OPT -cp $DEX_LOCATION/$TEST_NAME.jar$SECONDARY_DEX Main $@"
cmdfile=$(tempfile -p "cmd-" -s "-$TEST_NAME")
echo "$cmdline" > $cmdfile

if [ "$DEV_MODE" = "y" ]; then
  echo $cmdline
fi

if [ "$QUIET" = "n" ]; then
  adb push $cmdfile $DEX_LOCATION/cmdline.sh
else
  adb push $cmdfile $DEX_LOCATION/cmdline.sh > /dev/null 2>&1
fi

adb shell sh $DEX_LOCATION/cmdline.sh

rm -f $cmdfile
